﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xww.Task;
using System.Text.RegularExpressions;

namespace Xww.LCV.Generator {
    public class ThresholdRelativeRegexGenerator : BaseGenerator {
        /*
        public LCSCollection FromStrings_Old(IEnumerable<string> lines, MiningParam param) {
            List<LCS> rst = new List<LCS>();
            string TotalLines = string.Join(Environment.NewLine, lines.ToArray());

            var firstStepLCSs = FirstStep(lines, param, TotalLines);
            //不要长度为2的LCV
            //rst.AddRange(firstStepLCSs);
            ICollection<LCS> IterationStepLCS = new HashSet<LCS>(firstStepLCSs, LCS.InstanceForHash);
            int IterationStep = 0;
            while (IterationStepLCS.Count>1) {
                var groups = IterationStepLCS.GroupBy(o => o.SubFirstLCS, LCS.InstanceForHash);

                IterationStep += 1;
                int sum = 0;
                foreach (var item in groups) {
                    int innerGroupCount = item.Count()-1;
                    sum += innerGroupCount * (innerGroupCount + 1) / 2;
                }
                ProgressStatus status = new ProgressStatus( sum, string.Format("Interation step 【{0}】, generating LCV of length {1} from {2} LCVs", IterationStep, IterationStep +2, IterationStepLCS.Count));

                ICollection<LCS> currentLCS = new List<LCS>();
                foreach (var group in groups) {
                    var sortedGroup = group.OrderBy(o=>o.LastLocation).ToArray();
                    for (int i = 0; i < sortedGroup.Length - 1; i++) {
                        LCS the = sortedGroup[i];
                        for (int j = i + 1; j < sortedGroup.Length; j++) {
                            LCS other = sortedGroup[j];
                            
                            status.ProgressOneStep();
                            StepChange(status);

                            if (the.LastLocation >= other.LastLocation)
                                continue;
                            LCS big = LCS.Imerge(the, other);
                            big.Support = big.REGEX.Matches(TotalLines).Count;
                            if (big.Support >= param.Threshold)
                                currentLCS.Add(big);
                        }
                    }
                    sortedGroup = null;
                }
                rst.AddRange(currentLCS);
                IterationStepLCS = currentLCS;
                GC.Collect();
            }
            return new LCSCollection(rst, "");
        }
        */

        const int MaxLCVLength = 10;

        public override LCSCollection FromStrings(IEnumerable<string> lines, MiningParam param) {
            List<LCS> rst = new List<LCS>();
            string TotalLines = string.Join(Environment.NewLine, lines.ToArray());

            var firstStepLCSs = this.FirstStep(lines, param.MaxInterval, param.Threshold);
            //不要长度为2的LCV
            HashSet<LCS> IterationStepLCS = firstStepLCSs;
            int LCVLengthInStep = 2;
            while (IterationStepLCS.Count > 1 && LCVLengthInStep<= MaxLCVLength) {

                HashSet<LCS> NotValidLCS = new HashSet<LCS>(LCS.InstanceForHash);

                var firsts = IterationStepLCS.GroupBy(o => o.SubFirstString).ToDictionary(o => o.Key, o => o);
                var lasts = IterationStepLCS.GroupBy(o => o.SubLastString).Where(o => firsts.ContainsKey(o.Key)).ToDictionary(o => o.Key, o => o);
                int total = 0;
                ProgressStatus count = new ProgressStatus(firsts.Count, string.Format("Grouping parant LCVs for merging bigger ones"));
                foreach (var item in lasts) {
                    StepChange(count);
                    total += item.Value.Count() * firsts[item.Key].Count();
                    count.ProgressOneStep();
                }

                ProgressStatus status = new ProgressStatus(total, string.Format("Interation step 【{0}】, generating LCV of length {1} from {2} LCVs", LCVLengthInStep, LCVLengthInStep + 2, IterationStepLCS.Count));

                HashSet<LCS> currentLCS = new HashSet<LCS>();
                foreach (var group in lasts) {
                    foreach (var the in group.Value) {
                        foreach (var other in firsts[group.Key]) {
                            StepChange(status);
                            status.ProgressOneStep();
                            // bigInterval 为新LCV的跨度间隔
                            int bigLastPosition =  other.LastLocation + the.Locations[1] - other.FirstLocation;
                            if (bigLastPosition > MaxLCVLength)
                                continue;

                            LCS big = LCS.ImergeFirstLast(the, other);
                            if (currentLCS.Contains(big) || NotValidLCS.Contains(big)) {
                                continue;
                            }
                            big.Support = lines.Count(o => Regex.IsMatch(o, big.RegexString));
                            big.DeleteRegexString();
                            if (big.Support >= param.Threshold)
                                currentLCS.Add(big);
                            else
                                NotValidLCS.Add(big);
                        }
                    }
                }
                rst.AddRange(currentLCS);
                IterationStepLCS = currentLCS;
                currentLCS = null;
                NotValidLCS = null;
                firsts = null;
                lasts = null;
                LCVLengthInStep++;
                GC.Collect();
            }
            return new LCSCollection(rst, "");
        }


        //private ICollection<LCS> FirstStep(IEnumerable<string> lines, MiningParam param, string TotalLines) {
        //    HashSet<LCS> noLCSs = new HashSet<LCS>(LCS.InstanceForHash);
        //    HashSet<LCS> rst = new HashSet<LCS>(LCS.InstanceForHash);
        //    ProgressStatus status = new ProgressStatus(lines.Count(), "First step : generating LCS of 2 units");
        //    foreach (string sequence in lines) {
        //        base.StepChange(status);
        //        status.ProgressOneStep();
        //        for (int first = 0; first < sequence.Length - 1; first++) {
        //            LCSUnit FirstUnit = new LCSUnit(sequence[first], 1);
        //            for (int second = first + 1; second < sequence.Length; second++) {
        //                int offset = second - first;
        //                //if (offset < param.MinInterval) continue;
        //                if (offset > param.MaxInterval || offset > MaxIntervalAtFirst+2) break;
        //                LCS seed = new LCS(new char[] { FirstUnit.AA, sequence[second] }, new int[] { 1, offset + 1 });
        //                    //new LCS(0, FirstUnit, new LCSUnit(sequence[second], offset + 1));
        //                if (noLCSs.Contains(seed) || rst.Contains(seed))
        //                    continue;
        //                seed.Support = lines.Count(o => Regex.IsMatch(o, seed.RegexString));
        //                seed.DeleteRegexString();
        //                    //Regex.Matches(TotalLines, seed.GetRegexString()).Count;
        //                    //seed.REGEX.Matches(TotalLines).Count;
        //                if (seed.Support >= param.Threshold)
        //                    rst.Add(seed);
        //                else
        //                    noLCSs.Add(seed);
        //            }
        //        }
        //    }
        //    noLCSs = null;
        //    GC.Collect();
        //    return rst;
        //}
    }
}
